#ifndef UTILITY_THREADLOCAL_H
#define UTILITY_THREADLOCAL_H

#include "Noncopyable.h"
#include "wrap/pthread.h"

template<typename T>
class ThreadLocal final
{
    static_assert(sizeof(T), "T must be complete type");

public:
    ThreadLocal(): _key{0} { Wrap::pthread_key_create_(&_key, &_DESTURCTOR); };
    ~ThreadLocal() { Wrap::pthread_key_delete_(_key); };

    T &value() const;

private:
    NONCOPYABLE(ThreadLocal);

    static void _DESTURCTOR(void *x) { delete static_cast<T *>(x); }

    pthread_key_t _key;
};

template<typename T>
T &ThreadLocal<T>::value() const {
    auto *key = static_cast<T *>(Wrap::pthread_getspecific_(_key));
    if (key == nullptr) {
        auto *keyNew = new T;
        Wrap::pthread_setspecific_(_key, static_cast<const void *>(keyNew));
        key = keyNew;
    }
    return *key;
}



#endif